package com.morpheus.zookeeper.api.client;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.morpheus.zookeeper.config.ZookeeperProperties;

@SuppressWarnings("all")
public class ZookeeperClient {
	private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperClient.class);
	public static final String CHARSET_UTF8 = "UTF-8";

	private ZookeeperProperties zookeeperProperties = null;
	private CuratorFramework curatorFramework = null;

	public ZookeeperClient(CuratorFramework curatorFramework, ZookeeperProperties zookeeperProperties) {
		this.curatorFramework = curatorFramework;
		this.zookeeperProperties = zookeeperProperties;
	}

	public CuratorFramework getCuratorFramework() {
		return curatorFramework;
	}

	private String getParentPath(String nodePath) {
		String path = StringUtils.replaceChars(nodePath, "\\", "/");
		String parentPath = StringUtils.substring(path, 0, StringUtils.lastIndexOf(path, "/"));
		return parentPath;
	}

	public List<String> getChildren(String nodePath) {
		List<String> list = new ArrayList<String>();
		try {
			Stat stat = this.curatorFramework.checkExists().forPath(nodePath);
			if (stat != null) {
				list = this.curatorFramework.getChildren().forPath(nodePath);
			}
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.getChildren(nodePath) throwable", th);
		}
		return list;
	}

	public boolean exists(String nodePath) {
		try {
			Stat stat = this.curatorFramework.checkExists().forPath(nodePath);
			boolean flag = (stat != null);
			return flag;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.exists(nodePath) throwable", th);
			throw new IllegalStateException(th);
		}
	}

	public String createPersistent(String nodePath, boolean recursion) {
		try {
			String parentPath = this.getParentPath(nodePath);
			Stat stat = this.curatorFramework.checkExists().forPath(parentPath);
			if (stat == null) {
				this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
						.forPath(parentPath);
			}
			String result = this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
					.forPath(nodePath);
			return result;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.createPersistent(nodePath, recursion) throwable", th);
		}
		return null;
	}

	public String createPersistentSequential(String nodePath, boolean recursion) {
		try {
			String result = null;
			String parentPath = this.getParentPath(nodePath);
			Stat stat = this.curatorFramework.checkExists().forPath(parentPath);
			if (stat == null) {
				this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
						.forPath(parentPath);
			}
			if (recursion) {
				result = this.curatorFramework.create().creatingParentsIfNeeded()
						.withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath(nodePath);
			} else {
				result = this.curatorFramework.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath(nodePath);
			}
			return result;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.createPersistentSequential(nodePath, recursion) throwable", th);
		}
		return null;
	}

	public String createEphemeral(String nodePath, byte[] data) {
		try {
			String parentPath = this.getParentPath(nodePath);
			Stat stat = this.curatorFramework.checkExists().forPath(parentPath);
			if (stat == null) {
				this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
						.forPath(parentPath);
			}
			String result = this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
					.forPath(nodePath, data);
			return result;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.createEphemeral(nodePath, data) throwable", th);
		}
		return null;
	}

	public String createEphemeral(String nodePath, String data) {
		try {
			String parentPath = this.getParentPath(nodePath);
			Stat stat = this.curatorFramework.checkExists().forPath(parentPath);
			if (stat == null) {
				this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
						.forPath(parentPath);
			}
			byte[] nodeData = data.getBytes(Charset.forName(CHARSET_UTF8));
			String result = this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
					.forPath(nodePath, nodeData);
			return result;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.createEphemeral(nodePath, data) throwable", th);
		}
		return null;
	}

	public String createEphemeralSequential(String nodePath, byte[] data) {
		try {
			String parentPath = this.getParentPath(nodePath);
			Stat stat = this.curatorFramework.checkExists().forPath(parentPath);
			if (stat == null) {
				this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
						.forPath(parentPath);
			}
			String result = this.curatorFramework.create().creatingParentsIfNeeded()
					.withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(nodePath, data);
			return result;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.createEphemeralSequential(nodePath, data) throwable", th);
		}
		return null;
	}

	public String createEphemeralSequential(String nodePath, String data) {
		try {
			String parentPath = this.getParentPath(nodePath);
			Stat stat = this.curatorFramework.checkExists().forPath(parentPath);
			if (stat == null) {
				this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
						.forPath(parentPath);
			}
			byte[] nodeData = data.getBytes(Charset.forName(CHARSET_UTF8));
			String result = this.curatorFramework.create().creatingParentsIfNeeded()
					.withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(nodePath, nodeData);
			return result;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.createEphemeralSequential(nodePath, data) throwable", th);
		}
		return null;
	}

	public boolean create(String nodePath, CreateMode createMode) {
		try {
			String parentPath = this.getParentPath(nodePath);
			Stat stat = this.curatorFramework.checkExists().forPath(parentPath);
			if (stat == null) {
				this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
						.forPath(parentPath);
			}
			this.curatorFramework.create().creatingParentsIfNeeded().withMode(createMode).forPath(nodePath);
			stat = this.curatorFramework.checkExists().forPath(nodePath);
			boolean flag = (stat != null);
			return flag;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.create(nodePath) throwable", th);
		}
		return false;
	}

	public boolean create(String nodePath, CreateMode createMode, boolean recursionCreate) {
		try {
			String parentPath = this.getParentPath(nodePath);
			Stat stat = this.curatorFramework.checkExists().forPath(parentPath);
			if (stat == null) {
				this.curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT)
						.forPath(parentPath);
			}
			if (recursionCreate) {
				this.curatorFramework.create().creatingParentsIfNeeded().withMode(createMode).forPath(nodePath);
			} else {
				this.curatorFramework.create().withMode(createMode).forPath(nodePath);
			}
			stat = this.curatorFramework.checkExists().forPath(nodePath);
			boolean flag = (stat != null);
			return flag;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.create(nodePath, recursionCreate) throwable", th);
		}
		return false;
	}

	public boolean updateData(String nodePath, byte[] data) {
		try {
			Stat stat = this.curatorFramework.checkExists().forPath(nodePath);
			if (stat != null) {
				this.curatorFramework.setData().forPath(nodePath, data);
			}
			stat = this.curatorFramework.checkExists().forPath(nodePath);
			boolean flag = (stat != null);
			return flag;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.updateData(nodePath, data) throwable", th);
		}
		return false;
	}

	public boolean updateData(String nodePath, String data, Charset charset) {
		try {
			Stat stat = this.curatorFramework.checkExists().forPath(nodePath);
			if (stat != null) {
				byte[] nodeData = data.getBytes(charset);
				this.curatorFramework.setData().forPath(nodePath, nodeData);
			}
			stat = this.curatorFramework.checkExists().forPath(nodePath);
			boolean flag = (stat != null);
			return flag;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.updateData(nodePath, data, charset) throwable", th);
		}
		return false;
	}

	public boolean delete(String nodePath) {
		try {
			Stat stat = this.curatorFramework.checkExists().forPath(nodePath);
			if (stat != null) {
				this.curatorFramework.delete().forPath(nodePath);
			}
			stat = this.curatorFramework.checkExists().forPath(nodePath);
			boolean flag = (stat == null);
			return flag;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.delete(nodePath) throwable", th);
		}
		return false;
	}

	public boolean delete(String nodePath, boolean recursion) {
		try {
			Stat stat = this.curatorFramework.checkExists().forPath(nodePath);
			if (stat != null) {
				if (recursion) {
					this.curatorFramework.delete().deletingChildrenIfNeeded().forPath(nodePath);
				} else {
					this.curatorFramework.delete().forPath(nodePath);
				}
			}
			stat = this.curatorFramework.checkExists().forPath(nodePath);
			boolean flag = (stat == null);
			return flag;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.delete(nodePath, recursion) throwable", th);
		}
		return false;
	}

	public boolean addNodeWatcher(String nodePath, Watcher watcher) throws Exception {
		byte[] nodeData = this.curatorFramework.getData().usingWatcher(watcher).forPath(nodePath);
		return true;
	}

	public boolean addPathWatcher(String nodePath, Watcher watcher) throws Exception {
		List<String> list = this.curatorFramework.getChildren().usingWatcher(watcher).forPath(nodePath);
		return true;
	}

	public boolean addNodeWatcher(String nodePath, CuratorWatcher watcher) throws Exception {
		byte[] nodeData = this.curatorFramework.getData().usingWatcher(watcher).forPath(nodePath);
		return true;
	}

	public boolean addPathWatcher(String nodePath, CuratorWatcher watcher) throws Exception {
		List<String> list = this.curatorFramework.getChildren().usingWatcher(watcher).forPath(nodePath);
		return true;
	}

	public void addConnectListener(ConnectionStateListener connectionStateListener) {
		this.curatorFramework.getConnectionStateListenable().addListener(connectionStateListener);
	}

	/**
	 * 监听数据变化
	 * 
	 * @param nodePath
	 * @param executor
	 * @param nodeCacheListener
	 * @return
	 */
	public boolean addNodeListener(String nodePath, Executor executor, NodeCacheListener nodeCacheListener) {
		try {
			final NodeCache nodeCache = new NodeCache(this.curatorFramework, nodePath, false);
			nodeCache.start(true);
			nodeCache.getListenable().addListener(nodeCacheListener, executor);
			return true;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.addNodeListener(nodePath, executor, nodeCacheListener) throwable", th);
		}
		return false;
	}

	/**
	 * 监听path变化
	 * 
	 * @param nodePath
	 * @param executor
	 * @param pathChildrenCacheListener
	 * @return
	 * @throws Exception
	 */
	public boolean addPathListener(String nodePath, Executor executor,
			PathChildrenCacheListener pathChildrenCacheListener) throws Exception {
		try {
			final PathChildrenCache childrenCache = new PathChildrenCache(this.curatorFramework, nodePath, true);
			childrenCache.start(StartMode.POST_INITIALIZED_EVENT);
			childrenCache.getListenable().addListener(pathChildrenCacheListener, executor);
			return true;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.addPathListener() throwable", th);
		}
		return false;
	}

	/**
	 * 删除节点监听器
	 * 
	 * @param nodePath
	 * @param executor
	 * @param nodeCacheListener
	 * @return
	 */
	public boolean removeNodeListener(String nodePath, Executor executor, NodeCacheListener nodeCacheListener) {
		try {
			final NodeCache nodeCache = new NodeCache(this.curatorFramework, nodePath, false);
			nodeCache.start(true);
			nodeCache.getListenable().removeListener(nodeCacheListener);
			return true;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.removeNodeListener() throwable", th);
		}
		return false;
	}

	/**
	 * 删除path监听
	 * 
	 * @param nodePath
	 * @param executor
	 * @param pathChildrenCacheListener
	 * @return
	 * @throws Exception
	 */
	public boolean removePathListener(String nodePath, Executor executor,
			PathChildrenCacheListener pathChildrenCacheListener) throws Exception {
		try {
			final PathChildrenCache childrenCache = new PathChildrenCache(this.curatorFramework, nodePath, true);
			childrenCache.start(StartMode.POST_INITIALIZED_EVENT);
			childrenCache.getListenable().removeListener(pathChildrenCacheListener);
			return true;
		} catch (Throwable th) {
			LOGGER.error("ZookeeperClient.removePathListener(nodePath, executor, pathChildrenCacheListener) throwable",
					th);
		}
		return false;
	}
}
